#ifndef __UTILS_H__
#define __UTILS_H__

#include <stm32f10x.h> 

#ifndef CNS01
#define CNS01   1
#define CNS03   3 
#define BA01    4
#endif

#define bool char
#define TRUE 1
#define FALSE 0
#define NULL 0

#define GET_MIN(A, B) (A > B ? B : A)
#define GET_MAX(A, B) (A > B ? A : B)

#define FLASH_HEX_ADDR      0x08040000
#define FLASH_FAILSAFE_ADDR 0x08003000
#define FLASH_APP_ADDR      0x08021800
#define FLASH_END           0x08080000
#define FLASH_PAGE_SIZE     0x800

/**
* Call this function before any other initializing.
*/
void vbb_EssentialInit(bool DebugMode);
bool vbb_DebugMode(void);
void vbb_SetDebugMode(bool DebugMode);

void vbb_DelayInit(void);
void vbb_DelayMillis(unsigned short Milliseconds);

void vbb_Reset(void);

/**
* In order to make my firmware support multiple models of 
* blackbox devices. I got to make this.
*/
void vbb_DeviceDetect(void);
char vbb_DeviceModel(void);

/**
* These functions will work with backup registers within the CPU,
* I used them to store the most important data because the size 
* of this memory is very limited.
*/ 
void vbb_BACKUP_Set(unsigned int RegId, unsigned short Value);
unsigned short vbb_BACKUP_Get(unsigned int RegId);
unsigned int vbb_BACKUP_GetInt(unsigned int RegId);
void vbb_BACKUP_SetInt(unsigned int RegId, unsigned int Value);
void vbb_BACKUP_Clear(void);

/**
* For every 2 minutes, if the device does not reset the 
* watchdog counter, device will reboot itself.
*/
void vbb_WatchDog_Init(char DeviceModel);
void vbb_WatchDog_CheckIn(void);

/**
* Flash read/write tools
*/
void vbb_INFLASH_ErasePage(unsigned int Address);
unsigned short vbb_INFLASH_ReadShort(unsigned int Address);
char vbb_INFLASH_ReadByte(unsigned int Address);
unsigned int vbb_INFLASH_Program(unsigned int Address, unsigned short Data); //Return 0 when program failed.

/**
* Print to terminal
*/
void vbb_OUTPUT_Init(void);
void vbb_OUTPUT_Deinit(void);
void vbb_OUTPUT_Print(const char * Text);
void vbb_OUTPUT_PrintDebug(const char * Text);
void vbb_OUTPUT_PrintNumberUnSigned(unsigned int Number);
void vbb_OUTPUT_PrintNumberSigned(int Number);
void vbb_OUTPUT_WriteByte(char Byte);

/**
* Pin is essential, so I put it in here
*/
#define PIN_MODE_GENERAL_OUTPUT_PUSH_PULL    0x03UL
#define PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL  0x0BUL
#define PIN_MODE_FLOATING_INPUT              0x04UL
#define PIN_MODE_ANALOG_INPUT                0x00UL
#define PIN_MODE_CLEAR                       0x0FUL

typedef struct
{
    GPIO_TypeDef *  GPIOx;
    uint32_t        p;    
    uint32_t        mode;
    uint8_t         on;
} VBB_Pin;

void vbb_PIN_Init(VBB_Pin * Pin, GPIO_TypeDef *  GPIOx, uint32_t P, uint32_t Mode);
void vbb_PIN_Set(VBB_Pin * Pin, bool On);
bool vbb_PIN_Get(VBB_Pin * Pin);

void vbb_LedSwitch(char Red, char Green);
void vbb_Buzz(unsigned int MilliCounter);

void vbb_IndependentWatchDogInit(void);

#endif
